//编译服务模块
#pragma once

#include<iostream>
#include<unistd.h>
#include<sys/wait.h>
#include<fcntl.h>

#include"../comm/util.hpp"//引入公共方法头文件
#include"../comm/log.hpp"//引入日志模块

namespace ns_compiler
{
    //展开路径拼接方法
    using namespace ns_util;

    //展开日志命名空间
    using namespace ns_log;

    class Compiler
    {
    public:
        Compiler()
        {}
        ~Compiler()
        {}

        //编译功能(成功：true 失败：false) 参数：代码文件名
        //临时文件处理:
        static bool Compile(const std::string& file_name)
        {
            pid_t res = fork();
            if(res < 0)
            {
                //子进程创建失败
                LOG(ERROR)<<"内部错误，创建子进程失败"<<"\n";

                return false; 
            }
            else if(res == 0)
            {
                umask(0);

                //打开错误文件(写方法打开，若文件不存在则创建)
                int _stderr = open(PathUtil::CompilerError(file_name).c_str(), O_CREAT | O_WRONLY, 0644);
                if(_stderr < 0)//判断是否文件打开成功
                {
                    LOG(WARNING)<<"没有成功形成stderr错误文件"<<"\n";
                    exit(1);
                }

                //stderr文件重定向(当编译错误时，将错误信息重定向写入到指定文件中)
                dup2(_stderr, 2);

                //子进程(程序替换：g++)
                //g++ -o 可执行程序名 源文件名 -std=c++11 所有的临时文件都放在temp路径中
                execlp("g++","g++","-o", PathUtil::Exe(file_name).c_str(), PathUtil::Src(file_name).c_str(), "-std=c++11", "-D","COMPILER_ONLINE",nullptr);
                LOG(ERROR)<<"启动g++编译器错误，程序替换失败，可能是参数错误"<<"\n";
                exit(2);
            }
            else
            {
                //父进程
                waitpid(res, nullptr, 0);//等待子进程
                //判断编译是否成功(可执行文件是否被生成)
                if(FileUtil::IsFileExists(PathUtil::Exe(file_name)))
                {
                    LOG(INFO)<<PathUtil::Src(file_name)<<"编译成功!"<<"\n";
                    return true;
                }
            }
            LOG(ERROR)<<"编译失败，没有形成可执行程序"<<"\n";
            return false;
        }

    };
}